﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using StringMath;

namespace PiCalculator
{
    class Program
    {
        const int INFINITY = 1000000;
        static void Main(string[] args)
        {
            System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
            int digitsToCalc = 1000000;
            MathString Pi = new MathString("3", "0");
            double numberofhexdigits = digitsToCalc / Math.Log(16);
            for (int i = 0; i < numberofhexdigits; )
            {
                int[] HexDigits = GetDigit(i,10);
                for (int j = 0; j < 10; j++)
                {
                    int ThisDigit = HexDigits[j];
                    MathString HexValue = MathString.Parse(ThisDigit);
                    MathString Exponent = new MathString("16", "0");
                    Exponent = Exponent ^ (i + 1);
                    HexValue = HexValue / Exponent;
                    Pi += HexValue;
                    i++;
                    Console.WriteLine(Pi);
                }
            }
        }
        static int GetDigit(int n)
        {
            /*
             * pi = 	4 sum(0 , inf, (1) / ((16^k)(8k+1))) 
             * - 2sum(0 , inf, (1) / ((16^k)(8k+4)))
             * - sum(0 , inf, (1) / ((16^k)(8k+5)))
             * - sum(0 , inf, (1) / ((16^k)(8k+6)))
             * sum1 = sum(0,n,(16^(n-k) % (8k + 1) / (8K + 1)) + sum(n + 1, inf, (16^(n-k))/(8k + 1))
             * sum2 = sum(0,n,(16^(n-k) % (8k + 4) / (8K + 4)) + sum(n + 1, inf, (16^(n-k))/(8k + 4))
             * sum3 = sum(0,n,(16^(n-k) % (8k + 5) / (8K + 5)) + sum(n + 1, inf, (16^(n-k))/(8k + 5))
             * sum4 = sum(0,n,(16^(n-k) % (8k + 6) / (8K + 6)) + sum(n + 1, inf, (16^(n-k))/(8k + 6))
             * */

            double sum1 = 0;
            double sum2 = 0;
            double sum3 = 0;
            double sum4 = 0;

            for (int k = 0; k <= n; k++)
            {
                double this1 = (double)(MemoryEfficientModulus(16, (n - k), (8 * k + 1))) / (double)(8 * k + 1);
                double this2 = (double)(MemoryEfficientModulus(16, (n - k), (8 * k + 4))) / (double)(8 * k + 4);
                double this3 = (double)(MemoryEfficientModulus(16, (n - k), (8 * k + 5))) / (double)(8 * k + 5);
                double this4 = (double)(MemoryEfficientModulus(16, (n - k), (8 * k + 6))) / (double)(8 * k + 6);
                sum1 += this1;
                sum2 += this2;
                sum3 += this3;
                sum4 += this4;
            }
            for (int k = n + 1; k < INFINITY; k++)
            {
                double this1 = (Math.Pow(16, n - k) / (8 * k + 1));
                double this2 = (Math.Pow(16, n - k) / (8 * k + 4));
                double this3 = (Math.Pow(16, n - k) / (8 * k + 5));
                double this4 = (Math.Pow(16, n - k) / (8 * k + 6));
                sum1 += this1;
                sum2 += this2;
                sum3 += this3;
                sum4 += this4;
            }
            double total = 4 * sum1 - 2 * sum2 - sum3 - sum4;
            double floor = Math.Floor(total);
            total -= floor;
            total = total * 16;

            int output = (int)Math.Floor(total);
            if (output < 0)
                output += 15;
            return output;
        }
        static int[] GetDigit(int start, int number)
        {
            /*
 * pi = 	4 sum(0 , inf, (1) / ((16^k)(8k+1))) 
 * - 2sum(0 , inf, (1) / ((16^k)(8k+4)))
 * - sum(0 , inf, (1) / ((16^k)(8k+5)))
 * - sum(0 , inf, (1) / ((16^k)(8k+6)))
 * sum1 = sum(0,n,(16^(n-k) % (8k + 1) / (8K + 1)) + sum(n + 1, inf, (16^(n-k))/(8k + 1))
 * sum2 = sum(0,n,(16^(n-k) % (8k + 4) / (8K + 4)) + sum(n + 1, inf, (16^(n-k))/(8k + 4))
 * sum3 = sum(0,n,(16^(n-k) % (8k + 5) / (8K + 5)) + sum(n + 1, inf, (16^(n-k))/(8k + 5))
 * sum4 = sum(0,n,(16^(n-k) % (8k + 6) / (8K + 6)) + sum(n + 1, inf, (16^(n-k))/(8k + 6))
 * */

            double sum1 = 0;
            double sum2 = 0;
            double sum3 = 0;
            double sum4 = 0;

            for (int k = 0; k <= start; k++)
            {
                double this1 = (double)(MemoryEfficientModulus(16, (start - k), (8 * k + 1))) / (double)(8 * k + 1);
                double this2 = (double)(MemoryEfficientModulus(16, (start - k), (8 * k + 4))) / (double)(8 * k + 4);
                double this3 = (double)(MemoryEfficientModulus(16, (start - k), (8 * k + 5))) / (double)(8 * k + 5);
                double this4 = (double)(MemoryEfficientModulus(16, (start - k), (8 * k + 6))) / (double)(8 * k + 6);
                sum1 += this1;
                sum2 += this2;
                sum3 += this3;
                sum4 += this4;
            }
            for (int k = start + 1; k < INFINITY; k++)
            {
                double this1 = (Math.Pow(16, start - k) / (8 * k + 1));
                double this2 = (Math.Pow(16, start - k) / (8 * k + 4));
                double this3 = (Math.Pow(16, start - k) / (8 * k + 5));
                double this4 = (Math.Pow(16, start - k) / (8 * k + 6));
                sum1 += this1;
                sum2 += this2;
                sum3 += this3;
                sum4 += this4;
            }
            double total = 4 * sum1 - 2 * sum2 - sum3 - sum4;
            double floor = Math.Floor(total);
            total -= floor;
            int[] output = new int[number];
            for (int i = 0; i < number; i++)
            {
                total = total * 16;

                int think = (int)Math.Floor(total);
                if (think < 0)
                    think += 15;
                total -= think;
                output[i] = think;
            }
            return output;
        }
        /// <summary>
        /// Modulus b^e % m
        /// </summary>
        /// <param name="b">Base</param>
        /// <param name="e">Exponent</param>
        /// <param name="m">Modulus</param>
        /// <returns></returns>
        static int MemoryEfficientModulus(int b, int e, int m)
        {
            int c = 1;
            int eprime = 0;
            while (eprime < e)
            {
                eprime++;
                c = (b * c) % m;
            }
            return c;

        }
        static char HexIntToHexChar(int HexInt)
        {
            if (HexInt < 10)
                return HexInt.ToString()[0];
            else
            {
                int location = HexInt +  55;
                char outopu = (char)location;
                return outopu;
            }
        }
    }
}
